/* Copyright 2017, 2018, Gabriel Czernikier
 *
 * This file is part of Notehaus.
 * Notehaus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Notehaus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Notehaus.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef __NH_UNRESOLVED_TYPE_H
#define __NH_UNRESOLVED_TYPE_H
#include<stdbool.h>
#include<types.h>
/* Line up progression from parser's semantic structures to Dalvik format. Center arround how the progression will occur for Dalvik item formats (eg. type_id_item) but also include auxiliary structures (like packages are for types) even if not directly represented in the Dalvik format.
 * UPSTREAM PASS:
 * Java 7 grammar's ReferenceType =thru (DOWNSTREAM-running) process P1 synthesizes into=> unresolved_type_id -acquainted by-> proto_id_item, field_id_item, method_id_item, et. al.
 * unresolved_type_id={RefTyp_group, search_context}
 * proto_id_item, field_id_item, method_id_item, et. al. = {unresolved_type_id} <<< this is the acquaintaince
 * the collection of unresolved_type_id, i.e. [unresolved_type_id] =goes thru (DOWNSTREAM-running) process P2 and produces=> [unresolved_type_id = {+type_id}] to be acquainted by proto_id_item, field_id_item, et. al. Thus for example [proto_id_item={type_id such that proto_id_item{unresolved_type_id} and unresolved_type_id={type_id}}]
 * DOWNSTREAM PASS:
 * PROCESS P1: SEARCH DATA (ENTRIES AND CONTEXT) OUT-MAKING, SEARCH BASED TYPE RESOLUTION DELAYING, IMMEDIATE TYPE DECLARATION RESOLUTION
 * B0, B1, B2... are parser macrostates, as per aproaching or leaving a referencetype_token is concerned
 * Bx: s -> a     is a triplete of parser macrostate, input token or string, action
 * S1, S2... are actions, possibly with annotated outbounds (the end product of the action).
 * B0: package_string -> new search_entry={package_string, search_entry_type="PAKAGE", parent={}}, search_pkg=search_entry, Parent=search_entry, goto B0 with search_context_item={ImportToken_group={"java" . "lang" . '*'}, search_context_type="IMPORT"}, goto B0, with search_context' substituted for search_context in search_context = search_context_item search_context'
 * B0: ImportToken_group-> search_context_item={ImportToken_group, search_context_type="IMPORT"}, goto B0, with search_context' substituted for search_context in search_context = search_context_item search_context'
 * B0: START_TypeDeclaration_FORMULA_STRING: search_context_item={search_pkg, search_context_type="ENTRY"}, goto B1, with the same substitution as above sentence
 * B1 (type defining macrostate): unqualif_RefTyp_token-> new search_entry={search_entry_string=unqualif_RefTyp_token, search_entry_type="REFTYP", parent=Parent}, add_type_id(str_dt'=perlish_map( {search_entry_string + search_entry_type=="PACKAGE"?'/':'$'} recursive_topdown_parent_produce(search_entry.parent)) + search_entry.search_entry_string), search_context_item={search_entry, search_context_type="ENTRY"}, Parent=search_entry, goto B2
 * B2 (type resolution delaying macrostate): END_ClassBody_FORMULA_STRING-> Parent=Parent->parent, goto B0 if Parent=search_pkg, else goto B1 with the converse substitution over search_context than that of B0
 * B2: START_TypeDeclaration_FORMULA_STRING-> goto B1 with the same substitution than that from B0
 * B2: RefTyp_group-> new unresolved_type_id={RefTyp_group, search_context} (UPSTREAM-observably production)
 *     Note: RefTyp_group's Context can be a method or field declaration, or a text (executable code) sentence. In all the cases,
 *     RefType_group can be either just a RefTyp_token or something like Identifier.Identifier.Identifier.RefTyp_token
 *     (i.e. qualified or unqualified). RefTyp_group may be regarded as a nonterminal symbol, as within structured grammars jargon. RefTyp_group is defined more formaly below.
 *
 * PROCESS P2: SEARCH BASED TYPE RESOLUTION OCCURRENCE, TYPE LINKAGE RESOLUTION
 * preconditions:
 * Let reftype_token be utmost_underived_reftyp_token(RefTyp_group). Have an array of search_entry, be it sorted by keys testable for equalness with reftyp_token (came from unresolved_type's), geared to quick searches and walking/steping throughout members of utmost_underived_reftyp_token(RefTyp_group) equivalence class. Design improvement: have the "PACKAGE" search_entries in a separate array, reachable from first array of search_entry children.
 * 
 * for each unresolved_type_id: str_dt=S4(RefTyp_group,search_context), unresolved_type_id={+type_id=add_type_id(str_dt)}, where {RefTyp_group, search_context}=unresolved_type_id (UPSTREAM-observably)
 *
 * S4 (search and match results) (RefTyp_group, search_context): outbound=fully qualified reftype's str_dt
 * Mid colloquial-formal object definition, for enabling a fluent pseudo code (from this definition it happens, on purpose, that search_context_item are yielded convertedly than how they were generated before, this is for picking search_context_item in a LIFO way).
 * search_context=search_context search_context_item
 * search_context=search_context_item
 * derive (search_context_item) means to substitute search_context_item' for search_context_item, where search_context=search_context_item search_context' and ( search_context'=search_context_item' search_context'' or search_context'=search_context_item' ) is true, or it's nonderivable otherwise
 * utmost_underived (search_context) is the head, i.e., the one wchich no other can derive to it, and from which every one else is derived, either directly or indirectly
 *
 * RefTyp_group = RefTyp_group reftype_token
 * RefTyp_group = reftype_token
 * derive (reftype_token) means to substitute reftype_token' for reftype_token, where RefTyp_group=RefTyp_group' reftype_token and ( RefTyp_group'=RefTyp_group'' reftype_token' or RefTyp_group'=reftype_token' ) is true, or it's nonderivable otherwise; reftyp_head_token is the utmost underived reftyp_token
 * utmost_underived (RefTyp_group) is the head, i.e., the one wchich no other can derive to it, and from which every one else is derived, either directly or indirectly
 *
 * ImportToken_group = ImportToken_group search_context_item_token
 * ImportToken_group = search_context_item_token
 * derive (search_context_item_token) means to substitute search_context_item_token' for search_context_item_token, where ImportToken_group=ImportToken_group' search_context_item_token and ( ImportToken_group'=ImportToken_group'' search_context_item_token' or ImportToken_group'=search_context_item_token' ) is true, or it's nonderivable otherwise; reftyp_head_token is the utmost underived reftyp_token
 * utmost_underived (ImportToken_group) is the head, i.e., the one wchich no other can derive to it, and from which every one else is derived, either directly or indirectly
 *
 * Matching Criterias 
 * Upon recycling (reentering the loop described by the following steps) move faster over search_entries than over search_context_item
 * 1) reftyp_token=utmost_underived_reftyp_token(RefTyp_group) == search_entry_string and search_entry_type == "REFTYP" => follow; otherwise match fails
 *    str_dt = search_entry_string
 *    follow table:
 *      reftyp_token is derivable => reftype_token=derive(reftype_token), search_entry=search_entry.parent, goto 2
 *      otherwise => goto 4
 * 2) reftyp_token == search_entry_string and search_entry_type == "REFTYP"  => follow; otherwise goto 3
 *    str_dt = search_entry_string + '$' + str_dt
 *    follow table:
 *      reftyp_token is derivable => reftype_token=derive(reftype_token), search_entry=search_entry.parent, goto 2
 *      otherwise => goto 4
 * 3) join('/', (reverse(recursive_derive(reftyp_token)) reftyp_token)) == search_entry_string and search_entry_type == "PACKAGE"  => match succeeds; otherwise match fails
 *    str_dt = search_entry_string + '/' + str_dt
 * 4 [search_context_type="IMPORT"]) search_context_item_token=utmost_underived_import_token(ImportToken_group)==reftyp_token or search_context_item_token == '*'=> follow; otherwise match fails
 *    follow table:
 *      search_context_item_token == '*' => search_context_item_token=derive(search_context_item_token), search_entry=search_entry.parent, goto 6
 *      otherwise  => search_context_item_token=derive(search_context_item_token), search_entry=search_entry.parent, goto 5
 * 5) search_context_item_token == search_entry_string and search_entry_type == "REFTYP" and search_context_item_token is derivable  => follow; otherwise goto 6
 *    str_dt = search_entry_string + '$' + str_dt
 *    follow table: search_context_item_token=derive(search_context_item_token), search_entry=search_entry.parent, goto 5
 * 6) join('/', (reverse(recursive_derive(search_context_item_token)) search_context_item_token)) == search_entry_string and search_entry_type == "PACKAGE" => match succeeds; otherwise match fails
 *    str_dt = search_entry_string + '/' + str_dt
 * 4 [search_context_type="ENTRY"]) search_context_item_entry==search_entry => match succeeds; match fails
 *   str_dt = perlish_map( {search_entry_string + search_entry_type=="PACKAGE"?'/':'$'} recursive_topdown_parent_produce(search_entry)) + str_dt
 *
 */

enum search_context_type_enu {
	IMPORT,
	ENTRY
}

// Members of search_context_stack: among search_context_items, each one is a context head thereof.
struct search_context_st {
	struct list_head context_head;   //struct search_context_item_st : items conforming this context.
	struct list_head context_head_list;   //struct search_context_st : contexts pushed onto a context stack
}

// Search contexts, narrow the search by telling whether any found target entry is *truly* selectable as a search match.
struct search_context_item_st {
	union {
		struct token_list_st *Import_particles;
       		struct search_entry_st *search_entry
	} search_context_item_entry;
	enum search_context_type_enu search_context_type;
	struct list_head search_context;   // A list which this search_context_item is member of.
};

void add_unresolved_type(struct token_list_st *RefTyp_group, struct search_context_st *search_context, struct type_id_st **type_id_to_resolve);

/* Adds a struct search_context_item_st*. If head is NULL returns a new head. Otherwise returns the same head.
 * Effectively, as a NULL is passed for head, a new search_context gets created.
 * Either Import_particles or search_entry must be NULL, conversely the other one must be not.*/
void add_search_context_item(struct token_list_st *Import_particles, struct search_entry_st * search_entry);
// For when a recursion is made into a state that requires a context copy.
struct search_context_st *push_search_context_copy();
struct search_context_st *pop_search_context();

#endif
